using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharedSource.SqlServer.MDDE.Middleware;
using System.Data.SqlClient;
using System.Xml;
using System.IO;

namespace Microsoft.SharedSource.SqlServer.MDDE.ManagementStudio
{
    public partial class UpdatePackage : Form
    {
        #region Fields

        string repositoryConnectionString;
        string templateName;
        string packageName;
        XmlDocument packageTree;
        XmlDocument configurableComponents;
        XmlDocument changesXml;
        XmlElement xnodeRoot;
        bool changesXmlLocked = false;

        #endregion

        #region Constructor

        public UpdatePackage(string repositoryConnectionString, string templateName, string packageName)
        {
            InitializeComponent();

            this.repositoryConnectionString = repositoryConnectionString;
            this.packageName = packageName;
            this.templateName = templateName;
        }

        #endregion

        #region Event handlers

        private void btnAddColumn_Click(object sender, EventArgs e)
        {
            // Locate the parent collection.
            XmlNode xnodeColumnCollection =
            (XmlNode)trvCollection.SelectedNode.Tag;

            // Locate the 'Columns' node.
            XmlNode xnodeColumns =
                xnodeColumnCollection.SelectSingleNode("./Columns");

            if (xnodeColumns == null)
                xnodeColumns =
                    UIHelper.AppendChildElement(
                    xnodeColumnCollection,
                    "Columns", null);

            // Add the 'Column' element 
            // to 'Columns' element.
            XmlElement xnodeColumn =
                UIHelper.AppendChildElement(
                xnodeColumns,
                "Column",
                new string[]{
                    "Name", Guid.NewGuid().ToString()});

            // Create a new treenode.
            TreeNode tnodeColumn =
                trvCollection.SelectedNode.Nodes.Add(
                xnodeColumn.Attributes["Name"].Value);

            // Add the xmlnode to treenode as a tag.
            tnodeColumn.Tag = xnodeColumn;

            // Select the new tree node.
            trvCollection.SelectedNode = tnodeColumn;

            // Bring the treenode in editable mode.
            tnodeColumn.BeginEdit();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            // Preserve the control states.
            Dictionary<Control, bool> initialState =
                new Dictionary<Control, bool>();
            foreach (Control ctrl in this.Controls)
            {
                initialState.Add(ctrl, ctrl.Enabled);
                ctrl.Enabled = false;
            }

            this.Cursor = Cursors.WaitCursor;

            this.Refresh();

            OperationResult result =
                MDDEManager.UpdatePackage(this.repositoryConnectionString,
                this.templateName, this.packageName, null, changesXml);

            StringBuilder sb = new StringBuilder();
            foreach (string str in result.OperationLog)
                sb.Append(str);

            if (result.SuccessStatus)
            {
                MessageBox.Show(
                    "Package updated successfully." + sb.ToString(),
                    "Success", MessageBoxButtons.OK,
                    MessageBoxIcon.Information);

                this.Close();
            }
            else
            {
                MessageBox.Show(
                    "Package updation failed." + sb.ToString(),
                    "Package Update Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }

            foreach (KeyValuePair<Control, bool> kvp in initialState)
                kvp.Key.Enabled = kvp.Value;

            this.Cursor = Cursors.Default;
        }

        private void btnRemoveColumn_Click(object sender, EventArgs e)
        {
            // Locate the associated column.
            XmlNode xnodeColumn =
            (XmlNode)trvCollection.SelectedNode.Tag;

            // Locate the 'Columns' node.
            XmlNode xnodeColumns =
                xnodeColumn.ParentNode;

            // Remove the column from xml node.
            xnodeColumns.RemoveChild(xnodeColumn);

            // Remove the column from treeview.
            trvCollection.SelectedNode.Remove();
        }

        private void dgCollections_Leave(object sender, EventArgs e)
        {
            // Return if the changes xml is locked.
            if (changesXmlLocked)
                return;

            // Recreate the 'Property' list 
            // in the associated property host.

            // Get the property host.
            XmlNode xnodePropertyHost =
                (XmlNode)trvCollection.SelectedNode.Tag;

            // Return if we do not have a property host.
            if (xnodePropertyHost == null)
                return;

            // Clear off all the properties.
            XmlNodeList removeThese =
                xnodePropertyHost.SelectNodes(
                "./Properties/Property");

            foreach (XmlNode xnodeProperty in removeThese)
                xnodeProperty.ParentNode.RemoveChild(xnodeProperty);

            // Recreate fresh properties.
            foreach (DataGridViewRow r in dgCollections.Rows)
            {
                if (r.Cells["dgCollectionsPropertyName"].
                    EditedFormattedValue.ToString() == "Name" ||
                    r.IsNewRow)
                    continue;

                // Locate element 'Properties'.
                XmlNode xnodeProperties =
                    xnodePropertyHost.SelectSingleNode("./Properties");
                if (xnodeProperties == null)
                    xnodeProperties =
                        UIHelper.AppendChildElement(
                        xnodePropertyHost,
                        "Properties", null);

                // Create the 'Property' element.
                XmlElement xnodeProperty =
                    UIHelper.AppendChildElement(
                    xnodeProperties, "Property",
                    new string[]{
                        "Name",
                        r.Cells["dgCollectionsPropertyName"].
                    EditedFormattedValue.ToString(),
                        "Value",
                        r.Cells["dgCollectionsPropertyValue"].
                    EditedFormattedValue.ToString()});
            }
        }

        private void dgCollections_RowValidating(
            object sender, DataGridViewCellCancelEventArgs e)
        {
            if (changesXmlLocked)
                return;

            // Validate the row, unless its a new row.
            if (e.RowIndex > dgCollections.Rows.Count)
                return;
            if (dgCollections.Rows[e.RowIndex].IsNewRow)
                return;

            // Check that the property name is specified.
            if (dgCollections.Rows[e.RowIndex].
                Cells["dgCollectionsPropertyName"].Value == null)
            {
                // Flag error message.
                MessageBox.Show("Property name cannot be empty.",
                    "Validation Failure",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);

                // Stay in the same row.
                e.Cancel = true;

                // Return.
                return;
            }

            // Verify that the same property name is not entered twice.
            for (int i = 0; i < dgCollections.Rows.Count; i++)
            {
                // Continue if it is the same/new row.
                if (i == e.RowIndex || dgCollections.Rows[i].IsNewRow)
                    continue;

                // If there is already this property name
                if (dgCollections.Rows[i].Cells["dgCollectionsPropertyName"].
                    Value.ToString().Equals(dgCollections.Rows[e.RowIndex].
                    Cells["dgCollectionsPropertyName"].Value.ToString(),
                    StringComparison.InvariantCultureIgnoreCase))
                {
                    // Flag error message.
                    MessageBox.Show("The property name already exists.",
                        "Validation Failure",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);

                    // Cancel event.
                    e.Cancel = true;

                    // Return
                    return;
                }
            }
        }

        private void dgMappings_Leave(object sender, EventArgs e)
        {
            string componentUri = null;
            string componentType = string.Empty;
            string componentName = string.Empty;

            GetComponentDetails(ref componentUri,
                ref componentName, ref componentType);

            // Proceed only if we have a configurable node selected.
            if (string.IsNullOrEmpty(componentUri) ||
                componentType == "Template")
                return;

            // Get the package node for this component.
            XmlElement packageComponent =
                (XmlElement)UIHelper.AppendComponent(xnodeRoot,
                componentType, componentName, componentUri);

            // Locate mappings in changes xml.
            XmlElement changesXmlMappings =
                (XmlElement)packageComponent.SelectSingleNode(
                "./Mappings");

            if (changesXmlMappings == null)
                changesXmlMappings =
                    UIHelper.AppendChildElement(
                    packageComponent, "Mappings", null);

            // Clear off the mappings.
            // NOTE: This statement assumes that 'Mappings' 
            // node does not have any default attributes.
            changesXmlMappings.RemoveAll();

            // Repopulate the mappings.
            foreach (DataGridViewRow r in dgMappings.Rows)
            {
                if (r.IsNewRow)
                    continue;

                string destinationColumn =
                    r.Cells["destinationColumn"].
                    EditedFormattedValue == null ?
                    string.Empty :
                    r.Cells["destinationColumn"].
                    EditedFormattedValue.ToString();

                bool blockPassThru =
                    ((r.Cells["blockPassThru"].Value != null) &&
                    (Convert.ToBoolean(
                    r.Cells["blockPassThru"].Value) == true)) ?
                    true : false;

                UIHelper.AppendChildElement(
                    changesXmlMappings, "Mapping",
                    new string[]{
                        "Usage",
                        blockPassThru?
                        "False":"True",
                        "SourceColumn",
                        r.Cells["sourceColumn"].
                        EditedFormattedValue.ToString(),
                        "DestinationColumn",
                        destinationColumn});
            }
        }

        private void dgMappings_RowValidating(
            object sender, DataGridViewCellCancelEventArgs e)
        {
            // Validate the row, unless its a new row.
            if (dgMappings.Rows[e.RowIndex].IsNewRow)
                return;

            // Do nothing if the changes xml is locked.
            if (changesXmlLocked)
                return;

            // Check that the source column value is specified.
            if (dgMappings.Rows[e.RowIndex].
                Cells["sourceColumn"].Value == null)
            {
                // Flag error message.
                MessageBox.Show("Source column name cannot be empty.",
                    "Validation Failure",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);

                // Stay in the same row.
                e.Cancel = true;

                // Return.
                return;
            }

            // Verify that same source/destination 
            // column is not entered twice.

            for (int i = 0; i < dgMappings.Rows.Count; i++)
            {
                // Continue if it is the same/new row.
                if (i == e.RowIndex || dgMappings.Rows[i].IsNewRow)
                    continue;

                // If there is already this source column.
                // NOTE: We are doing case-sensitive comparison here
                // so there might be chances of user entering two same
                // source column names.
                if (dgMappings.Rows[i].Cells["sourceColumn"].
                    Value.ToString().Equals(
                    dgMappings.Rows[e.RowIndex].
                    Cells["sourceColumn"].Value.ToString()))
                {
                    // Flag error message.
                    MessageBox.Show("The source column already exists.",
                        "Validation Failure",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);

                    // Cancel event.
                    e.Cancel = true;

                    // Return
                    return;
                }

                // If there is already this destination column
                if (dgMappings.Rows[i].Cells["destinationColumn"].
                    Value != null &&
                    dgMappings.Rows[e.RowIndex].Cells["destinationColumn"].
                    Value != null &&
                    dgMappings.Rows[i].Cells["destinationColumn"].
                    Value.ToString() ==
                    dgMappings.Rows[e.RowIndex].
                    Cells["destinationColumn"].Value.ToString())
                {
                    // Flag error message.
                    MessageBox.Show("The destination column already exists.",
                        "Validation Failure",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);

                    // Cancel event.
                    e.Cancel = true;

                    // Return
                    return;
                }
            }
        }

        private void dgProperties_CellValueChanged(
            object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0 || e.RowIndex > dgProperties.Rows.Count - 1)
                return;

            // Return if the changes xml is locked.
            if (changesXmlLocked)
                return;

            string componentUri = null;
            string componentType = string.Empty;
            string componentName = string.Empty;

            GetComponentDetails(ref componentUri,
                ref componentName, ref componentType);

            // Proceed only if we have a configurable node selected.
            if (string.IsNullOrEmpty(componentUri) ||
                componentType == "Template")
                return;

            // Append the changed property to changes Xml.
            UIHelper.AppendComponentProperty(
            xnodeRoot, componentName,
            componentType, componentUri,
            dgProperties.Rows[e.RowIndex].
            Cells["propertyName"].Value.ToString(),
            dgProperties.Rows[e.RowIndex].
            Cells["propertyValue"].Value == null ? null :
            dgProperties.Rows[e.RowIndex].
            Cells["propertyValue"].Value.ToString());
        }

        private void UpdatePackage_Load(object sender, EventArgs e)
        {
            // Get the package information.

            try
            {
                this.packageTree = MDDEManager.GetPackageTree(repositoryConnectionString,
                    templateName, packageName, "1.0.0.0");
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    "Could not retrieve the package information. \n" +
                    ex.Message, "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);

                this.Close();

                return;
            }

            //this.templateName =
            //    packageTree.FirstChild.Attributes["Template"].Value;

            // Fetch the configurable components list for the template.
            OperationResult result =
                MDDEManager.GetTemplateConfigurableComponents(
                this.repositoryConnectionString, this.templateName);

            if (result.SuccessStatus == false)
            {
                MessageBox.Show(
                    "Error getting the template information. \n" +
                    result.OperationLog[0],
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);

                this.Close();

                return;
            }
            else
                configurableComponents =
                    (XmlDocument)result.OperationOutputParameters[0];


            #region Initialize the changes xml.

            this.changesXml = new XmlDocument();
            XmlNode xChanges = MDDEManager.GetPackageDetails(repositoryConnectionString,
                templateName, packageName).SelectSingleNode("//ChangesFromTemplate");

            if (xChanges == null)
            {
                xnodeRoot =
                    changesXml.CreateElement("PackageChanges");

                changesXml.AppendChild(xnodeRoot);
            }
            else
            {
                changesXml.LoadXml(xChanges.InnerXml);

                xnodeRoot = (XmlElement)changesXml.FirstChild;
            }

            #endregion

            #region Display the package information.

            SqlConnectionStringBuilder cb = new SqlConnectionStringBuilder(
                this.repositoryConnectionString);
            lblRepository.Text = cb.DataSource + "." + cb.InitialCatalog;
            lblTemplate.Text = this.templateName;
            lblPackageName.Text = this.packageName;

            // Load the tempalte view.
            LoadTemplateView();

            // Load the package view.
            LoadPackageView();

            // Select the template tab.
            tabConfigComponents.SelectedIndex = 0;
            tabConfigComponents_SelectedIndexChanged(
                tabConfigComponents, new EventArgs());

            #endregion
        }

        private void tabConfigComponents_SelectedIndexChanged(
            object sender, EventArgs e)
        {
            if (tabConfigComponents.SelectedIndex == 0)
            {
                // Force a node selected change.
                trvTemplate.SelectedNode = trvTemplate.Nodes[0];
                trvTemplate_AfterSelect(trvTemplate,
                    new TreeViewEventArgs(
                    trvTemplate.Nodes[0], TreeViewAction.Unknown));
            }
            else if (tabConfigComponents.SelectedIndex == 1)
            {
                trvPackage.SelectedNode = trvPackage.Nodes[0];
                trvPackage_AfterSelect(trvPackage,
                    new TreeViewEventArgs(
                    trvPackage.Nodes[0], TreeViewAction.Unknown));
            }
        }

        private void tpgCollections_Leave(object sender, EventArgs e)
        {
            string componentUri = null;
            string componentName = string.Empty;
            string componentType = string.Empty;

            GetComponentDetails(
                ref componentUri, ref componentName, ref componentType);

            // Proceed only if we have a configurable node selected.
            if (string.IsNullOrEmpty(componentUri) ||
                componentType == "Template")
                return;

            // Get the changesxml node for this component.
            XmlNode xnodeComponent =
                UIHelper.AppendComponent(
                xnodeRoot, componentType,
                componentName, componentUri);

            // Find the collections information node.
            XmlNode xnodeCollectionInfo =
                xnodeComponent.SelectSingleNode(
                "./CollectionInformation");

            // Remove this node.
            if (xnodeCollectionInfo != null)
                xnodeCollectionInfo.ParentNode.
                    RemoveChild(xnodeCollectionInfo);

            // Add the new collection info.
            xnodeCollectionInfo = (XmlNode)trvCollection.Tag;
            if (xnodeCollectionInfo != null)
                xnodeComponent.AppendChild(xnodeCollectionInfo);
        }

        private void GetComponentDetails(ref string componentUri,
            ref string componentName, ref string componentType)
        {
            // Check which view is selected.
            if (tabConfigComponents.SelectedIndex == 0)
            {
                // Template view.
                XmlElement configComp =
                    (XmlElement)trvTemplate.SelectedNode.Tag;
                componentType =
                    configComp.HasAttribute("ComponentType") ?
                    configComp.Attributes["ComponentType"].Value :
                    string.Empty;
                componentName =
                    configComp.HasAttribute("ComponentName") ?
                    configComp.Attributes["ComponentName"].Value :
                    string.Empty;
                componentUri =
                    configComp.HasAttribute("ComponentUri") ?
                    configComp.Attributes["ComponentUri"].Value :
                    string.Empty;
            }

            if (tabConfigComponents.SelectedIndex == 1)
            {
                // Package view.
                XmlElement configComp =
                    (XmlElement)trvPackage.SelectedNode.Tag;
                componentType =
                    configComp.HasAttribute("Type") ?
                    configComp.Attributes["Type"].Value :
                    string.Empty;
                componentName =
                    configComp.HasAttribute("Name") ?
                    configComp.Attributes["Name"].Value :
                    string.Empty;
                componentUri =
                    configComp.HasAttribute("Uri") ?
                    configComp.Attributes["Uri"].Value :
                    string.Empty;
            }

            // There is difference in the component types of package tree and changes xml. 
            // Since the template configurations are generated from package tree, they get 
            // component types from their package trees.
            // Here translate the component types for package tree and template configurable
            // components to changes xml types.
            switch (componentType)
            {
                case "ConnectionManager":
                    componentType = "ConnectionManager";
                    break;
                case "Executable":
                case "Component":
                    componentType = "Component";
                    break;
                case "Variable":
                    componentType = "Variable";
                    break;
            }
        }

        private void trvCollection_AfterLabelEdit(
            object sender, NodeLabelEditEventArgs e)
        {
            // Change the name of newly added node.
            if (!string.IsNullOrEmpty(e.Label))
                ((XmlNode)e.Node.Tag).Attributes["Name"].Value = e.Label;
        }

        private void trvCollection_AfterSelect(
            object sender, TreeViewEventArgs e)
        {
            dgCollections.Rows.Clear();

            #region Enabling/disabling of controls.
            btnAddColumn.Enabled = false;
            btnRemoveColumn.Enabled = false;
            dgCollections.Enabled = false;

            if (e.Node.Tag != null)
            {
                XmlNode xnodePropertyHost = (XmlNode)e.Node.Tag;
                switch (xnodePropertyHost.Name)
                {
                    case "Column":
                        btnRemoveColumn.Enabled = true;
                        dgCollections.Enabled = true;
                        break;
                    case "Collection":
                        btnAddColumn.Enabled = true;
                        dgCollections.Enabled = true;
                        break;
                }

                #region Grid population

                foreach (XmlNode xnodeProperty
                    in xnodePropertyHost.SelectNodes(
                    "./Properties/Property"))
                {
                    dgCollections.Rows.Add(
                        xnodeProperty.Attributes["Name"].Value,
                        xnodeProperty.Attributes["Value"].Value);
                }

                #endregion
            }
            #endregion
        }

        private void trvCollection_BeforeLabelEdit(
            object sender, NodeLabelEditEventArgs e)
        {
            if (e.Node.Tag == null ||
                ((XmlNode)e.Node.Tag).Name != "Column")
                e.CancelEdit = true;
        }

        private void trvCollection_Validating(object sender, CancelEventArgs e)
        {
            // TODO: Verify that a column with same name is not added twice.
        }

        private void trvPackage_AfterSelect(
            object sender, TreeViewEventArgs e)
        {
            string componentName =
                ((XmlElement)(e.Node.Tag)).HasAttribute("Name") ?
                ((XmlElement)(e.Node.Tag)).Attributes["Name"].Value :
                string.Empty;
            string componentType =
                ((XmlElement)(e.Node.Tag)).HasAttribute("Type") ?
                ((XmlElement)(e.Node.Tag)).Attributes["Type"].Value :
                string.Empty;
            string componentUri =
                ((XmlElement)(e.Node.Tag)).HasAttribute("Uri") ?
                ((XmlElement)(e.Node.Tag)).Attributes["Uri"].Value :
                string.Empty;

            //isTemplateView = false;
            RefreshPropertyTabs(e, componentName, componentType,
                componentUri, false, false, false);
        }

        private void trvTemplate_AfterSelect(
            object sender, TreeViewEventArgs e)
        {
            XmlElement xComponent =
                (XmlElement)e.Node.Tag;
            string componentName =
                xComponent.HasAttribute("ComponentName") ?
                xComponent.Attributes["ComponentName"].Value :
                string.Empty;
            string componentType =
                xComponent.HasAttribute("ComponentType") ?
                xComponent.Attributes["ComponentType"].Value :
                string.Empty;
            string componentUri =
                xComponent.HasAttribute("ComponentUri") ?
                xComponent.Attributes["ComponentUri"].Value :
                string.Empty;

            RefreshPropertyTabs(e,
                componentName,
                componentType,
                componentUri,
                xComponent.HasAttribute("ContainsMappings") &&
                xComponent.Attributes["ContainsMappings"].Value == "False",
                xComponent.HasAttribute("ContainsCollections") &&
                xComponent.Attributes["ContainsCollections"].Value == "False", true);
        }

        private void PopulateMappings(XmlNode packageComp, bool isTemplateView)
        {
            XmlNode xConfigurableComponent = configurableComponents.SelectSingleNode(
               "//*[@ComponentUri=\"" + packageComp.Attributes["Uri"].Value + "\"]");

            if (isTemplateView && xConfigurableComponent.Attributes["ContainsMappings"].Value == "False")
            {
                dgMappings.Enabled = false;
                tpgMappings.Cursor = Cursors.No;
                return;
            }
            else
            {
                dgMappings.Enabled = true;
                tpgMappings.Cursor = Cursors.Default;
            }

            // Check if the changes xml has mappings information.
            XmlNode changesXmlMappings =
                changesXml.SelectSingleNode(
                "//*[@URL=\"" +
                packageComp.Attributes["Uri"].Value +
                "\"]/Mappings");

            // If not, populate the mappings tab from package tree xml.
            if (changesXmlMappings == null)
            {
                // Create a changes xml node.
                changesXmlMappings =
                    changesXml.CreateElement("Mappings");

                #region Add in the mappings.

                foreach (XmlNode packageMapping in
                    packageComp.SelectNodes(
                    "./Mappings"))
                {
                    // Add in the Mapping node.
                    XmlElement changesXmlMapping =
                        UIHelper.AppendChildElement(
                        changesXmlMappings,
                        "Mapping",
                        new string[]{
                        "Usage",
                        packageMapping.Attributes["Usage"].Value,
                        "SourceColumn",
                        packageMapping.Attributes["SourceColumn"].Value,
                        "DestinationColumn",
                        packageMapping.Attributes["DestinationColumn"].Value});
                }

                #endregion
            }

            // Populate the mappings tab from changes xml.
            foreach (XmlNode changesXmlMapping in
                changesXmlMappings.SelectNodes(
                "./Mapping"))
            {
                int i = dgMappings.Rows.Add(
                    changesXmlMapping.Attributes["SourceColumn"].Value,
                    Convert.ToBoolean(changesXmlMapping.
                    Attributes["Usage"].Value) ? false : true,
                    changesXmlMapping.Attributes["DestinationColumn"].Value);
            }

            // Finally, tag the grid.
            dgMappings.Tag = changesXmlMappings;
        }

        #endregion

        #region Helper methods

        private void PopulateCollections(XmlNode packageComponent, bool isTemplateView)
        {
            XmlNode xConfigurableComponent = configurableComponents.SelectSingleNode(
               "//*[@ComponentUri=\"" + packageComponent.Attributes["Uri"].Value + "\"]");

            if (isTemplateView && xConfigurableComponent.Attributes["ContainsCollections"].Value == "False")
            {
                dgCollections.Enabled = false;
                trvCollection.Enabled = false;
                tpgCollections.Cursor = Cursors.No;
                return;
            }
            else
            {
                dgCollections.Enabled = true;
                tpgCollections.Cursor = Cursors.Default;
            }

            // Check if the changes xml has collection information.
            XmlNode changesXmlCollectionInfo =
                changesXml.SelectSingleNode(
                "//*[@URL=\"" +
                packageComponent.Attributes["Uri"].Value +
                "\"]/CollectionInformation");

            // If not, populate the collections tab from package tree xml.
            if (changesXmlCollectionInfo == null)
            {
                // Create a changes xml node.
                changesXmlCollectionInfo =
                    changesXml.CreateElement("CollectionInformation");

                #region Add in the inputs.

                foreach (XmlNode packageCollection in
                    packageComponent.SelectNodes(
                    "./Node[@Name=\"Inputs\" or @Name=\"Outputs\"]/Node[@Type=\"Input\" or @Type=\"Output\"]"))
                {
                    // Add in the Collection node.
                    XmlElement changesXmlCollection =
                        UIHelper.AppendChildElement(
                        changesXmlCollectionInfo,
                        "Collection",
                        new string[]{
                        "Name",
                        packageCollection.Attributes["Name"].Value,
                        "Type",
                        packageCollection.Attributes["Type"].Value});

                    #region Add in collection properties.

                    XmlNodeList packageCollectionProperties =
                        packageCollection.SelectNodes("./Property");

                    if (packageCollectionProperties.Count > 0)
                    {
                        XmlElement changesXmlCollectionProperties =
                            UIHelper.AppendChildElement(
                            changesXmlCollection,
                            "Properties", null);

                        foreach (XmlNode packageCollectionProperty in
                            packageCollectionProperties)
                        {
                            XmlElement changesXmlCollectionProperty =
                                UIHelper.AppendChildElement(
                                changesXmlCollectionProperties,
                                "Property",
                                new string[]{
                                "Name",
                                packageCollectionProperty.Attributes["Name"].Value,
                                "Value",
                                packageCollectionProperty.Attributes["Value"].Value});
                        }
                    }

                    #endregion

                    #region Add in the columns.

                    XmlElement changesXmlColumns =
                        UIHelper.AppendChildElement(
                        changesXmlCollection, "Columns", null);

                    foreach (XmlNode packageColumn in
                        packageCollection.SelectNodes(
                        "./Node[@Name=\"Columns\"]/Node[@Type=\"Column\"]"))
                    {
                        XmlElement changesXmlColumn =
                            UIHelper.AppendChildElement(
                            changesXmlColumns, "Column",
                            new string[] { 
                            "Name",
                            packageColumn.Attributes["Name"].Value});

                        // Add in the column properties.
                        XmlNodeList packageColumnProperties =
                            packageColumn.SelectNodes(
                            "./Property");

                        if (packageColumnProperties.Count > 0)
                        {
                            XmlElement changesXmlColumnProperties =
                                UIHelper.AppendChildElement(
                                changesXmlColumn, "Properties", null);

                            foreach (XmlNode packageColumnProperty
                                in packageColumnProperties)
                                UIHelper.AppendChildElement(
                                    changesXmlColumnProperties,
                                    "Property",
                                    new string[]{
                                        "Name",
                                        packageColumnProperty.Attributes["Name"].Value,
                                        "Value",
                                        packageColumnProperty.Attributes["Value"].Value});
                        }
                    }

                    #endregion
                }

                #endregion
            }

            // Populate the collections tab from changes xml.
            foreach (XmlNode xnodeInput in
            changesXmlCollectionInfo.SelectNodes(
            "./Collection[@Type=\"Input\"]"))
            {
                TreeNode tnodeColumnCollection =
                    trvCollection.Nodes[0].
                    Nodes["Input Collection"].Nodes.Add(
                    xnodeInput.Attributes["Name"].Value);
                tnodeColumnCollection.Tag = xnodeInput;

                // Add in the columns.
                foreach (XmlNode xnodeColumn in
                    xnodeInput.SelectNodes(
                    "./Columns/Column"))
                {
                    TreeNode tnodeColumn =
                        tnodeColumnCollection.Nodes.Add(
                        xnodeColumn.Attributes["Name"].Value);
                    tnodeColumn.Tag = xnodeColumn;
                }
            }

            // Populate the treeview outputs.
            foreach (XmlNode xnodeOutput in
                changesXmlCollectionInfo.SelectNodes(
                "./Collection[@Type=\"Output\"]"))
            {
                TreeNode tnodeColumnCollection =
                    trvCollection.Nodes[0].
                    Nodes["Output Collection"].Nodes.Add(
                    xnodeOutput.Attributes["Name"].Value);
                tnodeColumnCollection.Tag = xnodeOutput;

                // Add in the columns.
                foreach (XmlNode xnodeColumn in
                    xnodeOutput.SelectNodes(
                    "./Columns/Column"))
                {
                    TreeNode tnodeColumn =
                        tnodeColumnCollection.Nodes.Add(
                        xnodeColumn.Attributes["Name"].Value);
                    tnodeColumn.Tag = xnodeColumn;
                }
            }

            // Finally, tag the treeview.
            trvCollection.Tag = changesXmlCollectionInfo;
        }

        private void LoadPackageView()
        {
            TemplateComponentNode tn =
                new TemplateComponentNode(packageTree.DocumentElement);

            tn.PopulateSubtree();

            trvPackage.Nodes.Add(tn);

            trvPackage.Nodes[0].Expand();
        }

        private void LoadTemplateView()
        {
            // Get the root template node and add it to treeview.
            XmlNode xmlRoot =
                configurableComponents.SelectSingleNode("//Template");

            TreeNode trvRoot =
                trvTemplate.Nodes.Add(
                xmlRoot.Attributes["ComponentName"].Value);
            trvRoot.Name = trvRoot.Text;
            trvRoot.Tag = xmlRoot;

            // Create treenodes for each configurable component.
            foreach (XmlNode xmlConfigComp in xmlRoot.SelectNodes(
                "./ConfigurableComponent"))
            {
                TreeNode trvConfigComp = new TreeNode(
                    xmlConfigComp.Attributes["ComponentName"].Value);
                trvConfigComp.Name = trvConfigComp.Text;
                trvConfigComp.Tag = xmlConfigComp;
                trvRoot.Nodes.Add(trvConfigComp);
            }

            trvTemplate.ExpandAll();
        }

        private void RefreshPropertyTabs(
            TreeViewEventArgs e, string componentName, string componentType,
            string componentUri, bool forceDisablingOfMappings,
            bool forceDisablingOfCollections, bool isTemplateView)
        {
            // Lock the changes xml.
            changesXmlLocked = true;

            // Clear off controls.
            dgProperties.Rows.Clear();
            dgMappings.Rows.Clear();
            trvCollection.SelectedNode = trvCollection.Nodes[0];
            trvCollection.Nodes[0].Nodes["Input Collection"].Nodes.Clear();
            trvCollection.Nodes[0].Nodes["Output Collection"].Nodes.Clear();
            dgCollections.Rows.Clear();
            lblComponentName.Text = string.Empty;
            lblComponentType.Text = string.Empty;
            rtxComponentUri.Text = string.Empty;

            // Show the node name being selected.
            lblComponentName.Text = e.Node.Name;

            // Proceed only if we have a configurable node selected.
            if (string.IsNullOrEmpty(componentUri) ||
                componentType == "Template")
            {
                dgMappings.Enabled = false;
                tpgMappings.Cursor = Cursors.No;

                trvCollection.SelectedNode = trvCollection.Nodes[0];
                trvCollection.Enabled = false;
                dgCollections.Enabled = false;
                tpgCollections.Cursor = Cursors.No;
                return;
            }

            // Get the package component from Uri.
            XmlNode packageConfigComponent =
                packageTree.SelectSingleNode("//*[@Uri=\"" +
                componentUri + "\"]");

            // Return if component not found.
            if (packageConfigComponent == null)
                // Bug if you reach here.
                return;

            // Change label texts.
            lblComponentType.Text = componentType;
            rtxComponentUri.Text = componentUri;

            // Disable mappings and collections grid if the node 
            // is not associated with a data flow component.
            if (componentType != "Component")
            {
                dgMappings.Enabled = false;
                tpgMappings.Cursor = Cursors.No;

                trvCollection.Enabled = false;
                dgCollections.Enabled = false;
                tpgCollections.Cursor = Cursors.No;
            }
            else
            {
                if (!forceDisablingOfMappings)
                {
                    dgMappings.Enabled = true;
                    tpgMappings.Cursor = Cursors.Default;
                }

                if (!forceDisablingOfCollections)
                {
                    trvCollection.Enabled = true;
                    dgCollections.Enabled = true;
                    tpgCollections.Cursor = Cursors.Default;
                }
            }

            XmlNode templateConfigComponent = configurableComponents.SelectSingleNode(
               "//*[@ComponentUri=\"" + componentUri + "\"]");

            // Populate grid view
            foreach (XmlNode xnodeProperty in
            packageConfigComponent.SelectNodes("./Property"))
            {
                // Locate the property within the configurable component.
                XmlNode xConfigurableProperty = isTemplateView ? 
                    templateConfigComponent.SelectSingleNode(
                    "./ConfigurableProperty[@Name=\"" +
                    xnodeProperty.Attributes["Name"].Value + "\"]") : null;

                if (!isTemplateView ||
                    isTemplateView && xConfigurableProperty != null)
                {
                    // Check if the changes xml has this property node.
                    XmlNode changesXmlProperty = changesXml.SelectSingleNode(
                        "//*[@URL=\"" +
                        componentUri + "\"]/Properties/Property[@Name=\"" +
                        xnodeProperty.Attributes["Name"].Value + "\"]");

                    // If not, add the property with original value into the grid.
                    if (changesXmlProperty == null)
                        dgProperties.Rows.Add(
                            xnodeProperty.Attributes["Name"].Value,
                            xnodeProperty.Attributes["Value"].Value);
                    else
                        dgProperties.Rows.Add(
                            xnodeProperty.Attributes["Name"].Value,
                            changesXmlProperty.Attributes["Value"].Value);
                }
            }

            // Populate the mappings grid.
            PopulateMappings(packageConfigComponent, isTemplateView);

            // Populate the collections treeview and properties grid.
            PopulateCollections(packageConfigComponent, isTemplateView);

            // Release changes xml.
            changesXmlLocked = false;
        }

        #endregion
    }
}

